package org.vacoor.ticket.service;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

import org.vacoor.ticket.Constant;
import org.vacoor.ticket.bean.SeatType;
import org.vacoor.ticket.bean.Station;
import org.vacoor.ticket.bean.TicketDto;
import org.vacoor.ticket.bean.TimeRegionType;
import org.vacoor.ticket.bean.TrainPassType;
import org.vacoor.ticket.bean.TrainType;
import org.vacoor.ticket.bean.option.OrderState;
import org.vacoor.ticket.bean.option.Train;
import org.vacoor.ticket.bean.param.impl.BookingParam;
import org.vacoor.ticket.bean.param.impl.LoginParam;
import org.vacoor.ticket.bean.param.impl.OrderParam;
import org.vacoor.ticket.bean.param.impl.SimpleParam;
import org.vacoor.ticket.bean.param.impl.TicketQueryParam;
import org.vacoor.ticket.bean.param.impl.TrainParam;
import org.vacoor.ticket.exception.BookingTicketException;
import org.vacoor.ticket.exception.CheckOrderException;
import org.vacoor.ticket.exception.ExecuteException;
import org.vacoor.ticket.exception.InitException;
import org.vacoor.ticket.exception.LoginException;
import org.vacoor.ticket.exception.QueryException;
import org.vacoor.ticket.executor.defaults.DefaultExecutor;
import org.vacoor.ticket.handler.impl.BookingResultHandler;
import org.vacoor.ticket.handler.impl.CheckOrderHandler;
import org.vacoor.ticket.handler.impl.ImageResultHandler;
import org.vacoor.ticket.handler.impl.LoginRandCodeResultHandler;
import org.vacoor.ticket.handler.impl.LoginResultHandler;
import org.vacoor.ticket.handler.impl.OrderStateResultHandler;
import org.vacoor.ticket.handler.impl.SimpleHandler;
import org.vacoor.ticket.handler.impl.TicketQueryResultHandler;
import org.vacoor.ticket.handler.impl.option.SubmitOrderResultHandler;
import org.vacoor.ticket.handler.impl.option.TrainResultHandler;

public class TicketService {
	/**
	 * 这个方法等价与initQuery(false,from, arrive, date, region, passType, trainType, trainCode);
	 * @param from
	 * @param arrive
	 * @param date
	 * @param region
	 * @param passType
	 * @param trainType
	 * @param trainCode
	 * @return
	 * @throws InitException
	 */
	public static TicketQueryParam initQuery(Station from,Station arrive,
			Date date,TimeRegionType region,TrainPassType passType,TrainType[] trainType,String trainCode) throws InitException {
		return initQuery(false,from, arrive, date, region, passType, trainType, trainCode);
	}
	
	/**
	 * 初始化参数
	 * @param isStuQuery	//是否是学生票查询,这个测试不影响结果
	 * @param from
	 * @param arrive
	 * @param date
	 * @param region
	 * @param passType
	 * @param trainType
	 * @param trainCode
	 * @return
	 * @throws InitException
	 */
	public static TicketQueryParam initQuery(boolean isStuQuery,Station from,Station arrive,
			Date date,TimeRegionType region,TrainPassType passType,TrainType[] trainType,String trainCode) throws InitException {
		try {
			String trainNo = "";
			// ---------------------------------------------
			// 获取指定车次相关信息
			if (trainCode != null && !"".equals(trainCode)) {
				TrainParam trainQuery = new TrainParam(from.getCode(), arrive.getCode(), date, region);
				//这个是列车编号不是车次
				List<Train> trains = DefaultExecutor.execute(Constant.QUERY_TRAIN_URL, trainQuery, "GET", new TrainResultHandler());
				int i = 0;
				for (i = 0; i < trains.size(); i++) {
					Train t = trains.get(i);
					if (t.getCode().toUpperCase().contains(trainCode.toUpperCase())) {
						System.out.println("得到给定车次信息:" + t);
						trainNo = t.getNo();
						break;
					}
				}
				if (i >= trains.size()) {
					trainNo = "";
					System.out.println("没有设置车次或车次设置有误,忽略车次设置");
				}
			}
			return new TicketQueryParam(isStuQuery, from, arrive, date, region, passType, trainType, trainNo);
		}catch (Exception e) {
			throw new InitException(e.getMessage());
		}
	}
	
	
	/**
	 * 登录
	 * 
	 * @param username 
	 *            登录用户名
	 * @param passwd
	 * 			  登录密码
	 * @param loopCount
	 *            重试次数
	 * @throws ExecuteException 
	 * @throws LoginException 
	 */
	public static void login(String username,String passwd, int loopCount) throws ExecuteException, LoginException {
		int result = 1;
		String title = "登录验证码";
		//当用户名/密码错误,验证码错误时并且没有超过指定次数时,再次登录
		for (int i = 0; 
				(result == LoginResultHandler.ERR_NAME_PASSWD
				|| result == LoginResultHandler.ERR_AUTHCODE) 
				&& i < loopCount; i++) {
			// 获取验证码
			ImageIcon authIcon = DefaultExecutor.execute(Constant.LOGIN_AUTH_URL,new SimpleParam(Math.random() + ""), "GET",new ImageResultHandler());
			String code = (String)JOptionPane.showInputDialog(null, "请输入左侧验证码,取消或关闭退出程序", title, JOptionPane.OK_CANCEL_OPTION,authIcon, null, null);
			System.out.println("输入验证码:" + code);
			if(code == null) {
				System.exit(0);
			}
			// 获取随机登录码
			String rand = "";
			int j = 0;
			while (j<10 && "".equals(rand)) {
				rand = DefaultExecutor.execute(Constant.LOGIN_RAND_CODE_URL,new SimpleParam("_=" + new Date().getTime()), "GET",new LoginRandCodeResultHandler());
				System.out.println("获取随机登录码:" + rand);
				if ("".equals(rand)) {
					System.out.println("获取随机登录码失败,即将重试");
					continue;
				}
				j++;
			}
			if(j>10) {
				throw new LoginException("无法获取随机验证码");
			}
			// 登录
			result = DefaultExecutor.execute(Constant.LOGIN_URL,new LoginParam(username, passwd, code, rand), "POST",new LoginResultHandler());
			System.out.println("登录响应码:" + result + "("+ (result == 0 ? "成功)" : "失败)"));
			switch (result) {
			case LoginResultHandler.ERR_NAME_PASSWD:
				title = "用户名或密码不正确";
				break;
			case LoginResultHandler.ERR_AUTHCODE:
				title = "验证码错误";
				break;
			case LoginResultHandler.ERR_MAINTENANCE:
				title = "系统维护";
				break;
			case LoginResultHandler.ERR_ILLEGAL_REQ:
				title = "访问被拒绝";
				break;
			case LoginResultHandler.ERR_UNKNOW:
				title = "未知错误,可能12306代码已经改变";
				break;
			}
		}
		if(result != LoginResultHandler.OK_SUCCESS) {
			throw new LoginException(title);
		}
	}
	
	/**
	 * 获取所有可以订购的票
	 * @param ticketQuery
	 * @param seatType
	 * @param ticketCout 车票数量,当小于该数值则排除
	 * @param isPrecision 是否绝对匹配,eg: 上海/上海虹桥当true时会忽略
	 * @param loopCount  当查询结果为0时候,循环查询次数
	 * @return
	 */
	public static List<TicketDto> queryTickets(TicketQueryParam ticketQuery,SeatType seatType,int ticketCount,boolean isPrecision, long loopCount) {
		//等待时间
		int sleep = 1;
		// 查询余票
		List<TicketDto> tickets = null;
		String from = ticketQuery.getFromStation().getName();
		String arrive = ticketQuery.getArriveStation().getName();
		
		try {
			long count = 0;
			while (count < loopCount && tickets == null || tickets.size() == 0) {
				tickets = DefaultExecutor.execute(Constant.QUERY_TICKET_URL,ticketQuery, "GET", new TicketQueryResultHandler());
				// 过滤
				Iterator<TicketDto> it = tickets.iterator();
				while (it.hasNext()) {
					TicketDto d = it.next();
					System.out.println("获取到车票信息:" + d);
					// 过滤名称
					if (isPrecision) {
						if (!from.equals(d.getFromStationName()) || !arrive.equals( d.getArriveStationName())) {
							System.out.println("跳过非完全匹配: 目标-" + from + "\t找到-" + d.getFromStationName());
							it.remove();
							continue;
						}
					}
					// 过滤余票类型,不符合的删除
					// 这里硬座无座没有处理好?????????????????????????????????///
					int seatCount = d.getSeatInfo().get(seatType) != null ? d.getSeatInfo().get(seatType) : 0;
					System.out.println("目标座席:" + seatType.getName() + ",余票:" + seatCount + "张");
					if (seatCount < ticketCount) {
						System.out.println("跳过该车次" + d.getTrainCode());
						it.remove();
					}
				}
				if (tickets.size() == 0) {
					System.out.println("没有找到可购买车票," + sleep + "s后重试");
					Thread.sleep(sleep * 1000);
				}
			}
			if(count >= loopCount) {
				throw new Exception("查询超时,没有找到合适的票");
			}
		}catch(Exception e) {
			new QueryException(e.getMessage());
		}
		/*
		System.out.println("-------------------------");
		System.out.println("过滤后:");
		for (TicketDto d : tickets) {
			System.out.println(d);
		}
		*/
		return tickets;
	}
	
	/**
	 * 预订车票
	 * @return 订单信息
	 * @throws BookingTicketException 
	 * @throws ExecuteException 
	 */
	public static OrderParam bookingTicket(TicketQueryParam ticketQuery, TicketDto ticket) throws BookingTicketException, ExecuteException {
		System.out.println("开始尝试预订车票:" + ticket);
		//预定车票
		BookingParam bookingQuery = new BookingParam(ticketQuery, ticket);
		OrderParam order = DefaultExecutor.execute(Constant.ORDER_URL,	bookingQuery, "POST", new BookingResultHandler());
		switch (order.getStateCode()) {
			case BookingResultHandler.ERR_UNKNOW:
			case BookingResultHandler.ERR_HAVE_NO_FINISH:
			case BookingResultHandler.ERR_MAINTENANCE:
			case BookingResultHandler.ERR_ILLEGAL_REQ:
				throw new BookingTicketException(order.getMsg());
	//			System.out.println("非法请求");
	//			System.out.println(order.getMsg());
				//JOptionPane.showMessageDialog(null, order.getMsg() + "请处理完毕后运行本程序", "错误", JOptionPane.ERROR_MESSAGE);
				//System.exit(0);
		}
		return order;
	}
	
	/**
	 * 校验订单
	 * 在提交订单前必须执行
	 * @param order
	 * @throws ExecuteException
	 * @throws CheckOrderException
	 */
	public static void checkOrder(OrderParam order) throws ExecuteException, CheckOrderException {
		// 获取订单验证码
		String code = "";
		String msg = "";
		while ("".equals(code)) {
			ImageIcon authIcon = DefaultExecutor.execute( Constant.ORDER_AUTH_URL, new SimpleParam("" + Math.random()), "POST", new ImageResultHandler());
			code = (String) JOptionPane.showInputDialog(null, "请输入左侧验证码,取消或关闭退出程序", "订单验证码", JOptionPane.OK_CANCEL_OPTION, authIcon, null, null);
			if(code == null) {
				System.exit(0);
			}
			order.setRandCode(code);
			System.out.println("开始校验订单....");
			//校验订单
			msg = DefaultExecutor.execute(Constant.ORDER_CHECK_URL, order, "POST", new CheckOrderHandler());
			if(msg.contains("验证码")){
				code = "";
			}
		}
		System.out.println(msg);
		if (!"Y".equals(msg)) {
//			System.out.println("订单提交失败,错误信息:" + msg);
//			System.exit(0);
			throw new CheckOrderException("订单提交失败,错误信息:" + msg);
		}
	}
	
	/**
	 * 提交订单
	 * @param order
	 * @return 如果成功则返回"Y",失败返回错误信息
	 * @throws ExecuteException
	 */
	public static String submitOrder(OrderParam order) throws ExecuteException {
		System.out.println("提交订单信息....");
		String msg = DefaultExecutor.execute(Constant.ORDER_CONFIRM_URL, order,"POST", new SubmitOrderResultHandler());
		return msg.toUpperCase();
	}
	
	/**
	 * 检测订单是否成功
	 * @return 
	 * @throws ExecuteException
	 * @throws InterruptedException
	 */
	public static boolean checkOrderState() throws ExecuteException, InterruptedException {
		//获取订单处理信息,一旦执行,则必须重新从开始提交订单开始重新执行
		System.out.println("检测订单状态..");
		OrderState orderState = null;
		while(orderState == null || orderState.getStateCode() == OrderState.WAIT) {
			orderState = DefaultExecutor.execute(Constant.ORDER_WAIT_URL, null, "GET",	new OrderStateResultHandler());
//			System.out.println("订单状态信息:" + orderState.getMsg());
			System.out.println("等待服务器处理,可能还需要" + orderState.getWaitTime() +"s");
			Thread.sleep(1*1000);
		}
		if(orderState.getStateCode() != OrderState.OK_SUCCESS) {
			System.out.println(orderState.getMsg());
			return false;
		}
//		System.out.println("貌似成功,订单号:" + orderState.getOrderId());
		//因为如果本次订单提交失败,前面提交成功过订单,获取状态会是成功的状态
		//这里再次判断
//		System.out.println("再次检测...");
		Thread.sleep(2 * 1000);
		String msg = DefaultExecutor.execute(Constant.ORDER_NO_COMPLETE, null,	"GET", new SimpleHandler());
		//匹配是否有epayOrder('订单号'),'epay')这个是继续支付按钮上的信息
		Matcher m = Pattern.compile("epayOrder\\('[a-zA-Z0-9]+','epay'\\)").matcher(msg);
		if (m.find()) {
			msg = m.group();
//			System.out.println("订单成功");
			return true;
		}else {
//			System.out.println("订单失败...");
		}
		return false;
	}
}
